<?php
/*
 * @copyright: 有酱料
 * @author: Xinpow<xinpow@live.com>
 * @lang: zh_CN
 * @version: v1.0
 */
namespace Xinpow\Esign\Core;

use Xinpow\Esign\Config;

trait BaseHelper {

    public $connectTimeout = 30;  //30 second
    public $readTimeout    = 80;  //80 second
    public $_config;

    public function __construct() {
        $this->_config = new Config();
    }

    protected function fail($str, $data = []) {
        return $this->response(-1, $str, $data);
    }

    protected function success($str, $data = []) {
        return $this->response(0, $str, $data);
    }

    private function response($code, $str, $data = []){
        $res = [
            'errCode' => $code,
            'errShow' => $code === 0,
            'msg'     => $str,
        ];
        if($data) {
            $res['data'] = $data;
        }
        return $res;
    }

    protected function reject($handle, $fail_message = false) {
        if(is_array($handle)) {
            $handle = json_decode(json_encode($handle));
            if($handle->errCode != 0 && !$handle->msg && $fail_message) {
                $handle->msg = $fail_message;
            }
        }
        return $handle;
    }

    public function doPost($url, $data, $header = null){
        return $this->curl($url, 'POST', $data, $header);
    }

    public function doGet($url, $data, $header = null){
        return $this->curl($url, 'GET', $data, $header);
    }

    public function curl($url, $httpMethod = "GET", $postFields = null, $headers = [])
    {
        if(empty($headers)){
            $headers = ["Content-Type:application/json;charset=UTF-8"];
        }
        // $headers[] = 'Expect:';
        $logData = [
            'url'=>$url,
            'httpMethod'=>$httpMethod,
            'data'=>$postFields,
            'header'=>$headers
        ];

        $this->writeLog('curl data:');
        $this->writeLog($logData);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $httpMethod);
        // 代理服务器配置
        if($this->_config->proxy_config->enable_http_proxy) {
            curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
            curl_setopt($ch, CURLOPT_PROXY, $this->_config->proxy_config->http_proxy_ip);
            curl_setopt($ch, CURLOPT_PROXYPORT, $this->_config->proxy_config->http_proxy_port);
            curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
        }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_FAILONERROR, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $upfile = false;
        foreach ($headers as $v) {
            if(preg_match('/multipart\/form-data/i', $v)) {
                $upfile = true;
                break;
            }
        }
        $postData = (!$upfile && is_array($postFields)) ? json_encode($postFields,JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) : $postFields;
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);

        if ($this->readTimeout) {
            curl_setopt($ch, CURLOPT_TIMEOUT, $this->readTimeout);
        }
        if ($this->connectTimeout) {
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectTimeout);
        }
        //https request
        if(strlen($url) > 5 && strtolower(substr($url,0,5)) == "https" ) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }
        $headers[] = 'Expect:';
        if (is_array($headers) && 0 < count($headers))
        {
            curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
        }
        $curlRes = curl_exec($ch);
        
        $this->writeLog('curl response:');
        $this->writeLog($curlRes);

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if($httpCode != 200){
            throw new \Exception('curl http error:'.$httpCode);
        }
        $res = json_decode($curlRes);
        return $res ?: $curlRes;
    }

    public function postFile($url, array $keysArr = [])
    {
        static $disallow = array("\0", "\"", "\r", "\n");

        $body = [];
        foreach ($keysArr as $k => $v) {
            if ($k == 'file') {
                $data = self::getFileStream($v->name);
                if(is_array($data)){
                    return $data;
                }
                $srcPath = self::encodePath($v->name);
                $file = '@'.$srcPath;

                $body[] = implode("\r\n", array(
                    "Content-Disposition: form-data; name=\"file\"; filename=\"{$file}\"",
                    "Content-Type: application/octet-stream",
                    "",
                    $data,
                ));
            }

            $k = str_replace($disallow, "_", $k);
            $body[] = implode("\r\n", array(
                "Content-Disposition: form-data; name=\"{$k}\"",
                "",
                filter_var($v),
            ));
        }

        // generate safe boundary
        do {
            $boundary = "---------------------" . md5(mt_rand() . microtime());
        } while (preg_grep("/{$boundary}/", $body));

        // add boundary for each parameters
        array_walk($body, function (&$part) use ($boundary) {
            $part = "--{$boundary}\r\n{$part}";
        });

        // add final boundary
        $body[] = "--{$boundary}--";
        $body[] = "";

        $res = $this->doPost(
            $url,
            implode("\r\n", $body),
            $header = [
                "Content-Type: multipart/form-data; boundary={$boundary}",
            ]
        );
        return $res;
    }

    public static function getFileStream($filePath){
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $filePath);
        curl_setopt($curl, CURLOPT_REFERER, '');
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_HEADER, true); // 输出HTTP头 true
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);//SSL证书认证
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_TIMEOUT, 30);

        $result = curl_exec($curl);
        $httpCode = curl_getinfo($curl,CURLINFO_HTTP_CODE);

        if($httpCode != 200){
            if(isset($httpCodeMap[$httpCode])){
                return array('errCode'=>$httpCode, 'msg'=>'错误流数据');
            }
            $info['errCode'] = $httpCode;
            return $info;
        }
        return $result;
    }

    /**
     * 检查是否是中文编码
     * @param $str
     * @return int
     */
    public static function chkChinese($str)
    {
        return preg_match('/[\x80-\xff]./', $str);
    }

    /**
     * 检测是否windows系统，因为windows系统默认编码为GBK
     * @return bool
     */
    public static function isWin()
    {
        return strtoupper(substr(PHP_OS, 0, 3)) == "WIN";
    }

    /**
     * 主要是由于windows系统编码是gbk，遇到中文时候，如果不进行转换处理会出现找不到文件的问题
     * @param $file_path
     * @return string
     */
    public static function encodePath($file_path)
    {
        if (self::chkChinese($file_path) && self::isWin()) {
            $file_path = iconv('utf-8', 'gbk', $file_path);
        }
        return $file_path;
    }

    public static function getPostHttpBody($postFildes){
        $content = "";
        foreach ($postFildes as $apiParamKey => $apiParamValue)
        {
            if(is_string($apiParamValue)){
                $content .= "$apiParamKey=" . urlencode($apiParamValue) . "&";
            }
        }
        return substr($content, 0, -1);
    }
    public static function getHttpHearders($headers)
    {
        $httpHeader = [];
        foreach ($headers as $key => $value)
        {
            array_push($httpHeader, $key.":".$value);
        }
        return $httpHeader;
    }

    public function writeLog($text) {
        if(is_array($text) || is_object($text)){
            $text = json_encode($text);
        }
        // laravel函数
        $path = storage_path() . $this->_config->logs_path;
        if(!file_exists($path)){
            mkdir($path);
        }
        file_put_contents ( $path . "log_" . date('Y_m_d') . ".txt", date( "Y-m-d H:i:s" ) . "  " . strip_tags($text) . "\r\n", FILE_APPEND );
    }
}
